package com.itttq.tools.mybatis.util;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据库操作工具类
 *
 * @createTime: Jul 3, 2013 2:41:49 PM
 * @author: <a href="mailto:g2room@163.com">天涯</a>
 * @version: 0.1
 * @lastVersion: 0.1
 * @updateTime: 
 * @updateAuthor: <a href="mailto:g2room@163.com">天涯</a>
 * @changesSum: 
 * 
 */
public class DbUtil {
	private static DataSourceTo ds;
	public DbUtil(DataSourceTo dataSource) {
		ds = dataSource;
	}
	/**
	 * 获取数据库连接对象，这里只获得，需要自己在使用后进行关闭。
	 *
	 * @return 数据库连接实例
	 * @throws ClassNotFoundException 
	 * @throws SQLException 
	 * @auther <a href="mailto:g2room@163.com">天涯</a>
	 * Jul 6, 2013 8:49:25 PM
	 */
	public Connection getConn(DataSourceTo dataSource)
			throws ClassNotFoundException, SQLException {
		if(null == dataSource) {
			dataSource = ds;
		}
		// 1.加载驱动
		Class.forName(dataSource.getDriver());
		// 2.得到连接
		return DriverManager.getConnection(dataSource.getUrl(), dataSource
				.getUsername(), dataSource.getPassword());
	}
	/**
	 * 从数据源中获取字段名称及字段类型
	 * 
	 * @param ds
	 *            数据源配置Model，详见{@link:DataSourceModel}
	 * @param tableName
	 *            要获取字段的数据表名称
	 * @return Map<String, String>类型，key值为字段名，value为字段类型
	 * @auther <a href="mailto:g2room@163.com">天涯</a> Jul 28, 2013 4:11:07 PM
	 */
	public Map<String, String> getColumns(String tableName, boolean comment) {
		Map<String, String> columns = null;
		Connection conn = null;
		ResultSet rs = null;
		try {
			conn = getConn(ds);
			DatabaseMetaData metaData = conn.getMetaData();
			rs = metaData.getColumns(null, null, tableName, "");
			rs.last();
			columns = new HashMap<String, String>(rs.getRow());
			rs.first();
			columns.put(rs.getString("COLUMN_NAME")
					+ (comment ? " " + rs.getString("REMARKS") : ""),
					DbConstant.MAP_JDBC_JAVA_TYPE.get(rs
							.getInt("DATA_TYPE")));
		    while(rs.next()) {
		    	// COLUMN_NAME：字段名称
		    	// DATA_TYPE：字段数据类型(对应java.sql.Types中的常量)
		    	// TYPE_NAME：字段数据类型名称
		    	columns.put(rs.getString("COLUMN_NAME")
						+ (comment ? " " + rs.getString("REMARKS") : ""),
						DbConstant.MAP_JDBC_JAVA_TYPE.get(rs
								.getInt("DATA_TYPE")));
		    }
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if(null != rs) rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			closeConn(conn);
		}
		return columns;
	}
	
	/**
	 * 获取配置连接的所有数据库
	 *
	 * @param ds 数据源配置Model，详见{@link:DataSourceModel}
	 * @return 数据库名的List列表
	 * @auther <a href="mailto:g2room@163.com">天涯</a>
	 * Jul 28, 2013 12:29:34 PM
	 */
	public List<String> getDbName(){
		List<String> dbNames = new ArrayList<String>();
		Connection conn = null;
		ResultSet rs = null;
		try {
			conn = getConn(ds);
			DatabaseMetaData metaData = conn.getMetaData();
			rs = metaData.getCatalogs();
			rs.last();
			dbNames = new ArrayList<String>(rs.getRow());
			rs.first();
			dbNames.add(rs.getString("TABLE_CAT"));
		    while(rs.next()) {
		    	dbNames.add(rs.getString("TABLE_CAT"));
		    }
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if(null != rs) rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			closeConn(conn);
		}
		return dbNames;
	}
	public Map<String, String> getTablesByStatus() {
		// 记录表数据，key为表名，值为表注释
			Connection conn = null;
			ResultSet rs = null;
			Statement statement = null;
			Map<String, String> tables = new HashMap<String, String>();
			try {
				conn = getConn(ds);
				//SHOW TABLE STATUS
				String querySql = "SHOW TABLE STATUS";
				statement = conn.createStatement();
				rs = statement.executeQuery(querySql);
				while (rs.next()) {
					tables.put(rs.getString("Name"), rs.getString("Comment"));
				}
			}  catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					if(null != rs) rs.close();
					if(null != statement) statement.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				closeConn(conn);
			}
			return tables;
	}
	/**
	 * 获取所有的表名
	 *
	 * @param ds 数据源配置Model，详见{@link:DataSourceModel}
	 * @return 表名的List列表
	 * @auther <a href="mailto:g2room@163.com">天涯</a>
	 * Jul 28, 2013 12:26:22 PM
	 */
	public Map<String, String> getTables() {
		// 记录表数据，key为表名，值为表注释
		Connection conn = null;
		ResultSet rs = null;
		Map<String, String> tables = new HashMap<String, String>();
		try {
			conn = getConn(ds);
			DatabaseMetaData metaData = conn.getMetaData();
			/**
			 	第一个是数据库名称，对于MySQL，则对应相应的数据库，对于Oracle来说，则是对应相应的数据库实例，可以不填，也可以直接使用Connection的实例对象中的getCatalog()方法返回的值填充；
				第二个是模式，可以理解为数据库的登录名，而对于Oracle也可以理解成对该数据库操作的所有者的登录名。对于Oracle要特别注意，其登陆名必须是大写，不然的话是无法获取到相应的数据，而MySQL则不做强制要求。
				第三个是表名称，一般情况下如果要获取所有的表的话，可以直接设置为null，如果设置为特定的表名称，则返回该表的具体信息。
				第四个是类型标准,以数组形式传值，有"TABLE"、"VIEW"、"SYSTEM TABLE"、"GLOBAL TEMPORARY"、"LOCAL TEMPORARY"、"ALIAS" 和 "SYNONYM"这几个经典的类型，一般使用”TABLE”，即获取所有类型为TABLE的表
				
				返回一个ResultSet对象，有10列，详细的显示了表的类型：
					TABLE_CAT String => 表类别（可为 null）
					TABLE_SCHEM String => 表模式（可为 null）
					TABLE_NAME String => 表名称
					TABLE_TYPE String => 表类型。
					REMARKS String => 表的解释性注释
					TYPE_CAT String => 类型的类别（可为 null）
					TYPE_SCHEM String => 类型模式（可为 null）
					TYPE_NAME String => 类型名称（可为 null）
					SELF_REFERENCING_COL_NAME String => 有类型表的指定 "identifier" 列的名称（可为 null）
					REF_GENERATION String
			 */
			rs = metaData.getTables(conn.getCatalog(),null,null,new String[]{"TABLE"});
//			rs.last();
//			tables = new ArrayList<String>(rs.getRow());
			rs.first();
			tables.put(rs.getString("TABLE_NAME"), rs.getString("REMARKS"));
		    while(rs.next()) {
		    	tables.put(rs.getString("TABLE_NAME"), rs.getString("REMARKS"));
		    }
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if(null != rs) rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			closeConn(conn);
		}
		return tables;
	}
	
	/**
	 * 
	 * 关闭数据库连接。
	 *
	 * @param conn 数据库连接实例
	 * @auther <a href="mailto:g2room@163.com">天涯</a>
	 * Jul 11, 2013 5:06:44 PM
	 */
	public static void closeConn(Connection conn) {
		if(null != conn) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}